Canales en la región del infrarrojo
| Canal | Longitud de onda Central \(\mu m\) | Observaciones | Función de peso |
|---|---|---|---|
| 7 | 3.9 | Sensible tanto a la radiación del sol como a la emitida por la Tierra | Maxímo en superficie |
| 8 | 6.2 | Sensible al vapor de agua | Máximo en 425 hPa. |
| 9 | 6.9 | Predomina la absorción por vapor de agua | Maxímo cercano a 460 hPa. |
| 10 | 7.3 | Sensible al vapor de agua | Máximo en 640 hPa. |
| 11 | 8.4 | Para estudio de microfísica de nubes y plumas volcánicas con ceniza y dióxido de sulfuro | Máximo en niveles bajos |
| 12 | 9.6 | Absorción por ozono | Máximo en la estratósfera |
| 13 | 10.3 | Ventana radiativa, absorción despresiable en la atmósfera. Cerca del \(\lambda\) de máxima emisión terrestre | Máximo en superficie |
| 14 | 11.2 | Ventana radiativa con mayor absorción de vapor de agua | |
| 15 | 12.3 | Ventana radiativa con mayor absorción de vapor de agua | |
| 16 | 13.3 | Absorción por dióxido de carbono | Máximo cerca de superficie |
Al parecer las observaciones de GOES vienen en archivos .nc, uno por canal en radiancias.
## Aire claro
## Warning: Removed 8 rows containing missing values (geom_point).
## Warning: Removed 8 rows containing non-finite values (stat_bin).
## Warning: Removed 16 rows containing missing values (geom_point).
## Warning: Removed 16 rows containing non-finite values (stat_bin).
De acuerdo a la guía del usuario avanzda de GSI, para asimilar radiansas y que estas generen un impacto positivo en el prónosticos, es impresindible corregigir el bias asociado a cada instrumento y canal.
GSI corrige el BIAS sobre la diferencia entre la observación y el background teniendo en cuenta dos posibles fuentes de BIAS:
satbias_insatbias_angleAmbos set de coeficientes se deben ir actualizando en cada ciclo de asimilación, actualmente esa actualización se hace internamente (siempre que se configuren los argumentos necesarios en el namelist). De acuerdo a la guía los coeficientes para la correcciónn del bias tienen un spin up muy lento y deben ser entranados por semanas o meses. Una alternativa posibles es repetir cada ciclo de asimilación 10-12 veces antes de pasar al siguiente, cada vez actualizando los coeficientes.
Una tercera opción sería probar con los coeficientes que se guardas en GDAS y que usa GFS. No necesariamente es una buena solución ya que son modelos distintos con distinta resolución y dominio. Pero tal vez se puede partir de esos coeficientes para que el spin up sea más corto (en comparación con empezar en 0).
Queda por responder ¿cómo se que los coeficientes ya están bien entrenados y puedo usarlos?
Funciones de peso: http://tropic.ssec.wisc.edu/real-time/amsu/explanation.html
Maravillosamente los archivos en GDAS son de texto plano y tienen el formanto GSI friendly. Ahora me resulta obvio, pero nunca se sabe!
Entonces, hay un archivo cada 6 horas que se va actualizando.
Al parecer y de acuerdo a las versiones recientes de la guia de usuario, la correción del bias asociado al ángulo y el ¿modelos? ¿backgroud? se hace conjuntamente y por eso los coeficientes se combinan en un solo archivos.
# Es un archivo de texto plano, que emoción!!
satbias_in_file <- "/home/paola.corrales/datosmunin2/nomads.ncdc.noaa.gov/GDAS/201811/20181120/gdas.t00z.abias"
Para que la corrección se haga en conjunto es necesario indicarlo en el namelist: adp_anglebc = .true.
Archivos presentes en la salida de GSI
ana_file <- "/home/paola.corrales/datosmunin/EXP/analysis.ensmean"
ana <- ReadNetCDF(ana_file, vars = c(p = "P", "PB", t = "T", qv = "QVAPOR",
lon = "XLONG", lat = "XLAT")) %>%
.[, p := p + PB] %>%
.[, t := tk(t, p)] %>%
.[, rh := rh(qv, p, t)] %>%
.[, td := td(qv, p) + 273.15] %>%
.[, ":="(Time = NULL,
west_east = NULL,
south_north = NULL,
qv = NULL,
PB = NULL)] %>%
.[, c("u", "v") := uvmet(ana_file)] %>%
.[, file := "ana"]
guess_file <- "/home/paola.corrales/datosmunin/EXP/wrfarw.ensmean"
guess <- ReadNetCDF(guess_file, vars = c(p = "P", "PB", t = "T", qv = "QVAPOR",
lon = "XLONG", lat = "XLAT")) %>%
.[, p := p + PB] %>%
.[, t := tk(t, p)] %>%
.[, rh := rh(qv, p, t)] %>%
.[, td := td(qv, p) + 273.15] %>%
.[, ":="(Time = NULL,
west_east = NULL,
south_north = NULL,
qv = NULL,
PB = NULL)] %>%
.[, c("u", "v") := uvmet(ana_file)] %>%
.[, file := "guess"]
dt <- rbind(ana, guess)
dt[bottom_top %in% seq(1, 35, 4)] %>%
dcast(bottom_top + lon + lat ~ file, value.var = "t") %>%
.[, diff_t := ana - guess] %>%
ggplot(aes(lon, lat)) +
geom_point(aes(color = diff_t)) +
scale_color_divergent() +
geom_mapa() +
coord_sf(xlim = c(-78, -50), ylim = c(-42, -19)) +
facet_wrap(~ bottom_top) +
theme_minimal()
dt[bottom_top %in% seq(1, 35, 4)] %>%
dcast(bottom_top + lon + lat ~ file, value.var = "p") %>%
.[, diff_p := ana - guess] %>%
ggplot(aes(lon, lat)) +
geom_point(aes(color = diff_p)) +
scale_color_divergent() +
geom_mapa() +
coord_sf(xlim = c(-78, -50), ylim = c(-42, -19)) +
facet_wrap(~ bottom_top) +
theme_minimal()
En la etapa del LETKF la subrutina update_biascorr() se encarga de actualizar los coeficientes que se usan en la corrección del bias aplicando la metodología propuesta por Miyoshi et. al. (2010) y que según Zhu et. al. (2019) en análoga a la versión variacional que utiliza GSI. En el mismo paper indican que la optimización con filtro de kalman en algunos casos funciona mejor y esto podría doberse a que es menos sensible al tamaño de la muestra (cantidad de observaciones).
La rutina calcula el incremento de los coeficientes \(\delta \beta\) de la siguiente manera:
\[\delta \beta = (B_{\beta}^{-1} + P R^{-1}P^{T})^{-1}PR^{-1}[y-H(x)-P^T\beta]\]
Donde \(B^{-1}_\beta\) la matriz de covarianza de los coeficientes es diagonal y sus elementos valen 0.1.
La estimación de \(\delta \beta\) se realiza iterativamente tantas veces como el argumento numiter del namelist lo indique (por defecto 6).
Previamente al cálculo del incremento se realiza una estimación adaptativa de la varianza de los errores que impacta en la matriz \(B\). Actualmente el algoritmo tiene en cuenta:
Según el código los predictores \(p_i\) son:
Se calculan utilizando información del guess y de la observación de radianza y luego se utilizan para calcular la corrección del bias para cada observación y que será aplicada sobre el incremento.
\[ tbc = tbcnob + \sum_{i} p_i (\beta + \delta \beta)\]
files <- list.files("analisis/diagfiles/E7", pattern = "asim", full.names = TRUE)
diag <- map(files, function(f){
meta <- unglue::unglue(f, "analisis/diagfiles/{exp}/asim_{sensor}_{plat}_{date}.ensmean")
#print(f)
out <- fread(f)
# .[V10 == 1] %>%
if (file.size(f) != 0) {
out[, date := ymd_hms(meta[[1]][["date"]])]
}
out
}) %>%
rbindlist()
## Warning in fread(f): Stopped early on line 276. Expected 28 fields but found
## 27. Consider fill=TRUE and comment.char=. First discarded non-empty line:
## <<mhs_n19 1 -23.43 304.42 455.39 -0.09 99999997952.000000 99999997952.000000
## 99999997952.000000 0.000000 50.000000 0.950000 1.974102 -46.150002 82.910004
## 1.000000 0.000000 0.000000 0.000000******************** 0.545147E+00 0.100000E
## +01 0.000000E+00 0.000000E+00 0.169061E+01 0.130024E+01 0.000000E+00 0.000000E
## +00>>
## Warning in fread(f): Stopped early on line 896. Expected 28 fields but found
## 27. Consider fill=TRUE and comment.char=. First discarded non-empty line:
## <<mhs_n19 1 -22.45 287.04 0.00 -0.40 99999997952.000000 99999997952.000000
## 99999997952.000000 0.000000 50.000000 0.591223 0.283433 6.940000 259.660004
## 0.000000 0.000000 0.000000 9.000000******************** -0.155139E+00 0.100000E
## +01 0.000000E+00 0.000000E+00 0.152438E+00 -0.390433E+00 0.000000E+00 0.000000E
## +00>>
colnames(diag) <- c("sensor", "channel", "lat", "lon", "press", "dhr", "tb_obs", "tbc", "tbcnob",
"errinv", "qc", "emis", "tlapchn", "rzen", "razi", "rlnd", "rice", "rsnw", "rcld",
"rcldp", paste0("pred", seq(8)), "date")
diag[sensor == "amsua_n15" & channel %in% c(1:10)] %>%
melt(measure.vars = c("tbcnob", "tbc")) %>%
.[, .(mean = mean(value),
sd = sd(value)), by = .(variable, channel, date)] %>%
melt(measure.vars = c("mean", "sd"), variable.name = "estadistico") %>%
ggplot(aes(date, value)) +
geom_point(aes(color = variable)) +
geom_path(aes(color = variable, linetype = estadistico)) +
scale_color_brewer(name = NULL, palette = "Set1", labels = c("tbcnob" = "sin BC",
"tbc" = "con BC")) +
# geom_vline(xintercept = 0) +
facet_wrap(~channel, scales = "free") +
labs(x = "Obs - Guess") +
theme_minimal() +
theme(legend.position = "bottom")
diag[sensor == "amsua_n15" & channel %in% c(1:8)] %>%
.[date == date[1]] %>%
ggplot(aes(ConvertLongitude(lon), lat)) +
geom_point(aes(color = tbc - tbcnob)) +
scale_color_divergent(name = "BIAS") +
geom_mapa() +
coord_sf(xlim = c(-75, -52), ylim = c(-42,-20)) +
labs(title = "amsua_n15",
x = "", y = "") +
facet_wrap(~channel, ncol = 4) +
theme_minimal()
Pred2 = 1 Pred3 = 0 Pred7 = 0 Pred8 = 0
diag[sensor %in% c("amsua_n15")] %>%
ggplot(aes(factor(channel), tbc - tbcnob)) +
geom_hline(yintercept = 0, color = "darkorange") +
geom_boxplot() +
labs(x = "Channel", y = "BIAS") +
facet_wrap(~sensor) +
theme_minimal()
# diag[sensor %in% c("airs_aqua") & channel < 300] %>%
# ggplot(aes(channel, tbc - tbcnob)) +
# geom_boxplot(aes(group = channel))
files <- list.files("analisis/diagfiles/", pattern = "amsua_n15", full.names = TRUE)
diag <- map(files, function(f) {
var_names <- GlanceNetCDF(f) %>%
.$vars %>%
names()
diag <- ReadNetCDF(f, vars = var_names[c(10, 12, 13, 55:79)]) %>%
.[, file := f]
}) %>%
rbindlist()
diag[Channel_Index %in% c(1:4, 6, 7)] %>%
melt(measure.vars = c("Obs_Minus_Forecast_unadjusted", "Obs_Minus_Forecast_adjusted")) %>%
ggplot(aes(value)) +
geom_density(aes(color = variable)) +
geom_vline(xintercept = 0) +
facet_wrap(~Channel_Index, scales = "free") +
labs(x = "Obs - Guess") +
theme_minimal() +
theme(legend.position = "bottom")
diag %>%
melt(measure.vars = patterns("^BCPred_")) %>%
ggplot(aes(ConvertLongitude(Longitude), Latitude)) +
geom_point(aes(color = value)) +
scale_color_viridis_c() +
geom_mapa() +
coord_sf(xlim = c(-75, -52), ylim = c(-42,-20)) +
facet_wrap(~variable, ncol = 4) +
theme_minimal()
diag[Channel_Index == 2] %>%
ggplot(aes(ConvertLongitude(Longitude), Latitude)) +
geom_point(aes(color = Observation)) +
scale_color_viridis_c() +
geom_mapa() +
coord_sf(xlim = c(-75, -52), ylim = c(-42,-20)) +
# facet_wrap(~variable, ncol = 4) +
theme_minimal()